// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import TouchHandler from '../src/TouchHandler';

describe('TouchHandler Test Suites:', () => {
    let sendBuf = null;
    let player = null;
    let touchHandler = null;
    let playerSize = {
        width: 720,
        height: 1280
    };

    Element.prototype.getClientRects = jest.fn(() => {
        return [{
            width: playerSize.width,
            height: playerSize.height,
            top: 0,
            left: 0
        }];
    });

    const defaultSendHandler = function (buf) {
        sendBuf = buf;
    };

    function createPlayer() {
        const divCssText = `
            margin: 20px auto 10px;
            position: relative;
            width: 720px;
            height: 1280px;
            `;
        const videoCssText = `
            width: 720px;
            height: 1280px;
            object-fit: contain;
            display: block;
            `;
        let container = document.createElement('div');
        let player = document.createElement('video');
        player.id = 'playerId';
        container.id = 'containerId';
        container.style.cssText = divCssText;
        player.style.cssText = videoCssText;
        container.appendChild(player);
        return player;
    }

    function init(sendHandler) {
        player = createPlayer();
        touchHandler = new TouchHandler({
            player: player,
            isMobile: false,
            sendHandler: sendHandler || defaultSendHandler,
            isDebug: true
        });
        touchHandler.start();
    }

    function destroy() {
        touchHandler && touchHandler.destroy();
        if (player && player.parentNode) {
            player.parentNode.remove();
        } else if (player) {
            player.remove();
        }

        sendBuf = null;
        player = null;
        touchHandler = null;
    }

    function createMouseEvent(eventType, mouseCode) {
        return new MouseEvent(eventType || 'mousedown', {
            button: mouseCode || 0,
            pageX: 100,
            pageY: 100
        });
    }

    describe('synchronization', () => {
        beforeEach(() => {
            init();
        });

        afterEach(() => {
            destroy();
        });
    
        describe('Test vId management', () => {
            test('should alloc correct vId', () => {
                let vId = 0;
                for (let i = 0; i < 20; i++) {
                    vId = touchHandler.allocVirtualTouchId();
                    expect(vId).toBe(i);
                }

                vId = touchHandler.allocVirtualTouchId();
                expect(vId).toBe(0);
            });
    
            test('should can used again after free', () => {
                let vId = 0;
                for (let i = 0; i < 20; i++) {
                    vId = touchHandler.allocVirtualTouchId();
                }
    
                for (let i = 0; i < 20; i++) {
                    touchHandler.freeVirtualTouchId(i);
                }
    
                for (let i = 0; i < 20; i++) {
                    vId = touchHandler.allocVirtualTouchId();
                    expect(vId).toBe(i);
                }
            });
        });

        describe('Test mouse event', () => {
            test('should send mouse down msg', () => {
                let event = createMouseEvent('mousedown', 0);
                touchHandler.onMouseDown(event);
                const typedBuf = new Uint8Array(sendBuf);
                expect(typedBuf[9]).toBe(0);
            });

            test('should send mouse move msg', () => {
                let event = createMouseEvent('mousedown', 0);
                touchHandler.onMouseDown(event);
                event = createMouseEvent('mousemove', 0);
                touchHandler.onMouseMove(event);
                const typedBuf = new Uint8Array(sendBuf);
                expect(typedBuf[9]).toBe(2);
            });

            test('should send mouse up msg', () => {
                let event = createMouseEvent('mousedown', 0);
                touchHandler.onMouseDown(event);
                event = createMouseEvent('mouseup', 0);
                touchHandler.onMouseUp(event);
                const typedBuf = new Uint8Array(sendBuf);
                expect(typedBuf[9]).toBe(1);
            });

            test('should send mouse down msg when press down middle button', () => {
                let event = createMouseEvent('mousedown', 1);
                touchHandler.onMouseDown(event);
                const typedBuf = new Uint8Array(sendBuf);
                expect(typedBuf[9]).toBe(0);
            });

            test('should not send msg when free middle button', () => {
                let event = createMouseEvent('mousedown', 1);
                touchHandler.onMouseDown(event);
                sendBuf = null;
                event = createMouseEvent('mouseup', 1);
                touchHandler.onMouseUp(event);
                expect(sendBuf).toBeNull();
            });

            test('should send mouse up when press down middle button again', () => {
                let event = createMouseEvent('mousedown', 1);
                touchHandler.onMouseDown(event);
                event = createMouseEvent('mouseup', 1);
                touchHandler.onMouseUp(event);
                event = createMouseEvent('mousedown', 1);
                touchHandler.onMouseDown(event);
                const typedBuf = new Uint8Array(sendBuf);
                expect(typedBuf[9]).toBe(1);
            });
        });

        describe('Test getScale', () => {    
            test('should scale be 1', () => {
                const scale = touchHandler.getScale(720, 1280);
                expect(scale).toEqual({x: 1, y: 1});        
            });
    
            test('should scale less than 1', () => {
                const scale = touchHandler.getScale(800, 1300);
                expect(scale.x).toBeLessThan(1);
                expect(scale.y).toBeLessThan(1);
            });
    
            test('should scale greater than 1', () => {
                const scale = touchHandler.getScale(600, 1000);
                expect(scale.x).toBeGreaterThan(1);
                expect(scale.y).toBeGreaterThan(1);
            }); 
    
            test('should scale be 1, after change orientation', () => {
                touchHandler.updateOrientation('LANDSCAPE');
                const scale = touchHandler.getScale(720, 1280);
                expect(scale.x).toBeLessThan(1);
                expect(scale.y).toBeGreaterThan(1);
            });
        });
    
        describe('Test transform', () => {
            test('when the orientation of the display box and the game is the same', () => {
                let pos = touchHandler.transform({x: 0, y: 0});
                expect(pos).toEqual({x: 0, y: 0}); 
                pos = touchHandler.transform({x: 100, y: 100});
                expect(pos).toEqual({x: 100, y: 100}); 
            });
    
            test('when the orientation of the display box and the game is different', () => {
                // 通过修改player的宽高属性构造旋转
                const oldPlayerSize = Object.assign({}, playerSize);
                playerSize.width = oldPlayerSize.height;
                playerSize.height = oldPlayerSize.width;
                touchHandler.updateOrientation('LANDSCAPE');
                let pos = touchHandler.transform({x: 0, y: 0});
                expect(pos).toEqual({x: 720, y: 0});
                pos = touchHandler.transform({x: 100, y: 100});
                expect(pos).not.toEqual({x: 100, y: 100});
            });
        });
    });
});

